package com.lion.logclientstarter.service;

import com.lion.logclientstarter.bean.LogEntity;
import com.lion.logclientstarter.bean.LogParam;
import com.lion.logclientstarter.bean.LogPoint;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author linbin
 * @Description
 **/
@Slf4j
@Aspect
public class LogAspectj {

    @Value("${lion.log.trace:traceId}")
    private String trace;


    @Autowired
    private LogClient logClient;

    @Around("@annotation(com.lion.logclientstarter.bean.LogPoint)")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();

        LogEntity logEntity = new LogEntity();
        LogPoint logPoint = method.getAnnotation(LogPoint.class);

        logEntity.setCallSys(logPoint.callSys());
        logEntity.setLogName(logPoint.logName());
        logEntity.setLogSys(method.getDeclaringClass().getName()+"#"+method.getName());
        if (!StringUtils.isEmpty(trace)) {
            String traceId = MDC.get(trace);
            logEntity.setTraceId(traceId);
        }
        Map<String, String> logParam = new HashMap<>();
        //记录调用方信息与第三方接口信息
        Object[] params = pjp.getArgs();
        for (Object obj : params) {
            Map<String, String> tempLogParam = analyzeLogParam(obj);
            logParam.putAll(tempLogParam);
        }
        logEntity.setInParam(logParam);

        Object result = pjp.proceed();
        //获取返回数据中所需记录
        Map<String, String> outParam = analyzeLogParam(result);
        logParam.putAll(outParam);
        logEntity.setOutParam(outParam);
        //记录日志
        try {
            logClient.record(logEntity);
        } catch (Exception e) {
            log.error("处理日志:logEntity出现问题", e);
        }
        return result;
    }

    /**
     * 分析
     *
     * @param param
     * @return
     */
    private Map<String, String> analyzeLogParam(Object param) {
        Map<String, String> result = new HashMap<>();

        for (Field field : param.getClass().getDeclaredFields()) {
            try {
                if (field.getAnnotation(LogParam.class) != null) {
                    field.setAccessible(true);
                    LogParam logParam = field.getAnnotation(LogParam.class);
                    String paramValue = "";
                    switch (logParam.type()) {
                        case 1:
                            paramValue = field.get(param).toString();
                            break;
                        default:
                            paramValue = field.getName() + ":" + field.get(param).toString();
                            break;
                    }

                    result.put(logParam.key(), paramValue);
                    field.setAccessible(false);
                }
            } catch (IllegalAccessException e) {
                log.error("分析logParam出现异常:", e);
            }

        }
        return result;
    }

}
